package com.lagou.boot;

import com.lagou.client.RPCConsumer;
import com.lagou.service.IUserService;
import org.I0Itec.zkclient.IZkChildListener;
import org.I0Itec.zkclient.ZkClient;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @author czq
 * @date 2020/8/10 23:19
 */
public class ConsumerBoot {

    private static Map<String, IUserService> map = new HashMap<>();

    private static List<String> childrenList;

    public static void main(String[] args) throws InterruptedException {

        ZkClient zkClient = new ZkClient("127.0.0.1:2181");
        String path = "/lg-ZkClient";

        // 获取子节点信息
        childrenList = zkClient.getChildren(path);
        System.out.println("childrenList：" + childrenList);

        // 监听节点变化
        zkClient.subscribeChildChanges(path, new IZkChildListener() {
            @Override
            public void handleChildChange(String s, List<String> list) throws Exception {

                // 新增节点
                for (String str : list) {
                    if (!map.containsKey(str)) {
                        RPCConsumer rpcConsumer = new RPCConsumer();
                        map.put(str, (IUserService) rpcConsumer.createProxy(IUserService.class, str.split("_")[1]));
                        System.out.println("新增节点：" + str);
                    }
                }

                // 删除节点
                for (String children : childrenList) {
                    if (!list.contains(children)) {
                        map.remove(children);
                        System.out.println("删除节点：" + children);
                    }
                }

                System.out.println("变更后的子节点：" + list);

                childrenList = list;
            }
        });

        // 循环与各个节点的信息建立连接，并存储到 map 中
        for (String children : childrenList) {
            RPCConsumer rpcConsumer = new RPCConsumer();
            map.put(children, (IUserService) rpcConsumer.createProxy(IUserService.class, children.split("_")[1]));
        }

        // 2、循环给服务器写数据
        while (true) {

            // 当前调用的服务
            String server = "";
            long tempTime = 0;
            long currentTime = System.currentTimeMillis();

            for (String children : childrenList) {

                // 获取节点对应的值
                Object o = zkClient.readData(path + "/" + children);

                // 值为null表示响应时间超过5秒，直接失效忽略
                if (o == null) {
                    continue;
                }

                // init 表示第一次调用该节点，可直接选为调用对象
                if ("init".equals(o.toString())) {
                    server = children;
                    break;
                }

                // 计算响应时间
                long time = currentTime - Long.parseLong(o.toString());
                if (tempTime == 0) {
                    tempTime = time;
                    continue;
                }

                // 每次取最小响应时间的节点
                if (time < tempTime) {
                    server = children;
                    tempTime = time;
                }
            }

            // 如果 server 为空则表示当前所有节点的响应时间一致，则随机取一个节点作为调用节点
            if ("".equals(server)) {
                Random random = new Random();
                int num =random.nextInt(childrenList.size());
                server = childrenList.get(num);
            }

            System.out.println("调用的服务器：" + server);

            String result = map.get(server).sayHello("are you ok ？");
            System.out.println(result);
            Thread.sleep(3000);
        }
    }
}
